﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing.Design;
using System.ComponentModel;
using System.Windows.Forms.Design;
using ProgNetComponentsDx.Design.Designers;
using System.ComponentModel.Design;
using System.Collections;
using System.Windows.Forms;
using ProgNetComponents.Interfaces;
using EnvDTE;
using System.IO;

namespace ProgNetComponentsDx.Design.Editors
{
    public abstract class BaseGroupCollectionEditor : UITypeEditor
    {
        private ITypeDescriptorContext currentContext;
        private bool ignoreChangedEvents;
        private bool ignoreChangingEvents;
        IWindowsFormsEditorService edSvc = null;
        protected ITypeDescriptorContext Context
        {
            get
            {
                return this.currentContext;
            }
        }
        BaseGroupCollectionDesigner f = null;
        protected abstract BaseGroupCollectionDesigner CreateDesignerForm();
        protected abstract Type BaseNametype
        {
            get;
        }

        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            IDesignerHost designerHost = null;
            if (provider != null)
            {
                edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
                if (edSvc != null)
                {
                    this.currentContext = context;
                    ITypeDescriptorContext descriptorContext = this.currentContext;
                    this.ignoreChangingEvents = false;
                    this.ignoreChangedEvents = false;
                    f = CreateDesignerForm();
                    f.Collection = value as IList;

                    DesignerTransaction designerTransaction = null;
                    bool flag = true;
                    IComponentChangeService componentChangeService = null;
                    designerHost = provider.GetService<IDesignerHost>();
                    
                    try
                    {
                        try
                        {
                            if (designerHost != null)
                                designerTransaction = designerHost.CreateTransaction();
                        }
                        catch (CheckoutException ex)
                        {
                            if (ex == CheckoutException.Canceled)
                                return value;
                            else
                                throw new Exception("Exception occured", ex);
                        }
                        componentChangeService = designerHost != null ? (IComponentChangeService)designerHost.GetService(typeof(IComponentChangeService)) : (IComponentChangeService)null;
                        if (componentChangeService != null)
                        {
                            componentChangeService.ComponentChanged += new ComponentChangedEventHandler(this.OnComponentChanged);
                            componentChangeService.ComponentChanging += new ComponentChangingEventHandler(this.OnComponentChanging);
                        }
                        if (edSvc.ShowDialog(f) == DialogResult.OK)
                        {
                            GenerateEnumClass(provider, value as IList);
                        }
                        else
                            flag = false;
                    }
                    catch //(Exception ex)
                    {
                        //this.GetType().FullName.LogToFile();
                        //ex.Message.LogToFile();
                        //ex.StackTrace.LogToFile();
                    }
                    finally
                    {
                        this.currentContext = descriptorContext;
                        if (designerTransaction != null)
                        {
                            if (flag)
                                designerTransaction.Commit();
                            else
                                designerTransaction.Cancel();
                        }
                        if (componentChangeService != null)
                        {
                            componentChangeService.ComponentChanged -= new ComponentChangedEventHandler(this.OnComponentChanged);
                            componentChangeService.ComponentChanging -= new ComponentChangingEventHandler(this.OnComponentChanging);
                        }
                    }
                }
            }
            if (this.Context != null)
            {
                this.Context.OnComponentChanging();
                this.Context.OnComponentChanged();
            }
            if (f != null)
            {
                f.Dispose();
                f = null;
            }
            return value;
        }
        private string tab = "    ";

        protected virtual void GenerateEnumClass(IServiceProvider provider, IList collection)
        {
            if (provider != null)
            {
                DTE dte = provider.GetService<DTE>();
                if (dte != null)
                {
                    string file = dte.ActiveDocument.FullName;
                    string newFile = Path.GetDirectoryName(file) + "\\" + Path.GetFileNameWithoutExtension(file) + BaseNametype.Name+".cs";
                    string shortName = Path.GetFileName(newFile);

                    int max = dte.ActiveDocument.ProjectItem.ProjectItems.Count;
                    using(Stream fs = File.Open(newFile, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite)){
                        using (StreamWriter writer = new StreamWriter(fs, Encoding.UTF8))
                        {
                            IDesignerHost host = provider.GetService<IDesignerHost>();
                            if (host != null)
                            {
                                string ns = "";
                                string cn = "";
                                Type t = Type.GetType(host.RootComponentClassName);
                                if (t != null)
                                {
                                    ns = t.Namespace;
                                    cn = t.Name;
                                }
                                else
                                {
                                    int idx = host.RootComponentClassName.LastIndexOf('.');
                                    if (idx > 0)
                                    {
                                        ns = host.RootComponentClassName.Substring(0, idx);
                                        cn = host.RootComponentClassName.Substring(idx + 1);
                                    }
                                }
                                StringBuilder builder = new StringBuilder();

                                builder.AppendLine("namespace " + ns);
                                builder.AppendLine("{");
                                builder.AppendLine(tab + "public class " + cn + BaseNametype.Name + " : " + BaseNametype.FullName);
                                builder.AppendLine(tab + "{");
                                foreach (INamedGroup g in collection)
                                {
                                    WriteGroup(builder, g, 2);
                                }
                                builder.AppendLine(tab + "}");
                                builder.AppendLine("}");

                                writer.Write(builder.ToString());
                                writer.Flush();
                                writer.Close();
                                try
                                {
                                    dte.ActiveDocument.ProjectItem.ContainingProject.ProjectItems.AddFromFile(newFile);
                                }
                                catch { }
                            }
                        }
                    }
                }
            }
        }
        protected virtual void WriteGroup(StringBuilder builder, INamedGroup g, int tabs)
        {
            if (g.Items.Count > 0)
                ProgNetComponents.Tools.ConstHelper.AddEnums(builder, g.Name, g.Items, tabs);

            bool addGroup = false;
            foreach (INamedGroup g2 in g.Groups)
            {
                if (g2.HasAnyItems())
                {
                    addGroup = true;
                    break;
                }
            }
            if (addGroup)
            {
                ProgNetComponents.Tools.ConstHelper.AddClassStart(builder, g.Name + "_Group", tabs);
                
                foreach (INamedGroup g2 in g.Groups)
                {
                    if (g2.HasAnyItems())
                    {
                        builder.AppendLine();
                        WriteGroup(builder, g2, tabs + 1);
                    }
                }
                ProgNetComponents.Tools.ConstHelper.EndClass(builder, tabs);
            }
        }
        private void OnComponentChanged(object sender, ComponentChangedEventArgs e)
        {
            if (!this.ignoreChangedEvents && sender != this.Context.Instance)
            {
                this.ignoreChangedEvents = true;
                this.Context.OnComponentChanged();
            }
        }

        private void OnComponentChanging(object sender, ComponentChangingEventArgs e)
        {
            if (!this.ignoreChangingEvents && sender != this.Context.Instance)
            {
                this.ignoreChangingEvents = true;
                this.Context.OnComponentChanging();
            }
        }

        public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
        {
            return UITypeEditorEditStyle.Modal;
        }
    }
}
